using System;
using System.Collections.Generic;
using Biomedica.Propability.StateMachine;
using System.Threading;

namespace Biomedica.Propability.StateMachine
{
	public class StateMachineEngine   {
        public StateMachineEngine()
        {
            StateCollection = new Dictionary<string, State>();
            Delay = TimeSpan.FromMilliseconds(40);
        }
        public Dictionary<String,State> StateCollection { set; get; }
        public EventHandler<ChangeStateEventArgs> OnChangeStateEvent;
        private State currentState;
        private bool IsMachineStaretd;
        public StateContext Context { set; get; }
        String StartState;
        public State CurrentState { 
            set {
                currentState = value; 
                if (OnChangeStateEvent != null)OnChangeStateEvent(this, new ChangeStateEventArgs(currentState.Name)); 
            }
            get 
            {
                return currentState;
            } 
        }
		public void Run(StateContext context) {
            if (IsMachineStaretd)
                CurrentState.Test(context);
            else
                throw new NoStartStateException();
		}
        public void Start(String StartState,StateContext context)
        {
            currentState = StateCollection[StartState];
            IsMachineStaretd = true;
            Run(context);
        }
        public void SetOnEnterCallback(OnEnterCallback e, String State)
        {
            StateCollection[State].OnEnter = e;
        }
        public void SetOnExitCallback(OnExitCallback e, String State)
        {
            StateCollection[State].OnExit = e;
        }
        public void SetOnDoCallback(OnDoCallback e, String State)
        {
            StateCollection[State].OnDo = e;
        }
        public void SetTranstionCallbackForState(String fromState,String toState, OnTranstion e)
        {
            StateCollection[fromState].SetTrantionCallback(toState,e);
        }
        public void SetTranstionCallbackForState(String fromState, String toState,String TriggerParameter, OnTranstion e)
        {
            StateCollection[fromState].SetTrantionCallback(toState, e, TriggerParameter);
           
        }
        public void StartMachine(string p,StateContext context)
        {
            StartState = p;
            Context = context;
            IsRunning = true;
            Thread th = new Thread(new ThreadStart(Start));
            th.Start();
        }
        public void StopMachine()
        {
            IsRunning = false;
           
        }
        private void Start()
        {
            if (StartState != null && StateCollection.ContainsKey(StartState))
            {
                Start(StartState, Context);
                while (IsRunning)
                {
                    Run(Context);
                    System.Threading.Thread.Sleep(Delay);
                }
            }
            
        }
        public bool IsRunning { get; set; }
        public TimeSpan Delay { get; set; }

        internal void AddTransition(string p1, string p2, string p3)
        {
            StateCollection[p1].Add(new Triggers(p2,p3,true));
        }

        internal void Update(StateContext context)
        {
            Run(context);
        }
    }

}
